package com.wanwu.channel.core.util.apollo;

import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.openapi.client.ApolloOpenApiClient;
import com.ctrip.framework.apollo.openapi.dto.NamespaceReleaseDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenItemDTO;
import com.ctrip.framework.apollo.openapi.dto.OpenNamespaceDTO;
import com.wanwu.channel.common.enums.BusinessCodeEnum;
import com.wanwu.channel.common.enums.ExceptionEnum;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.LogUtil;
import com.wanwu.channel.core.util.apollo.config.ApolloOpenApiConfiguration;
import com.wanwu.channel.dao.entity.ChannelMerchantInfoEntity;
import com.wanwu.channel.dao.entity.ChannelPayEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * apollo关于商户配置的工具类
 * @Author chenshunxing
 * @Data 2020/07/20 14：28
 */
@Component
public class ApolloMerchantUtil {
    private static final Logger logger = LoggerFactory.getLogger(ApolloMerchantUtil.class);

    @Resource
    private ApolloOpenApiConfiguration apolloConfig;

    private static ApolloOpenApiClient client;

    @PostConstruct
    public void init() {
        client = ApolloOpenApiClient.newBuilder()
                .withPortalUrl(apolloConfig.getUrl())
                .withToken(apolloConfig.getToken())
                .build();
    }

    /**
     * 推送商户配置到apollo
     * @param entity
     * @return
     */
    public void pushItemToApollo(ChannelMerchantInfoEntity entity){
        String key=String.valueOf(entity.getId());
        String value=JSON.toJSONStringWithDateFormat(entity,"yyyy-MM-dd HH:mm:ss");
        OpenItemDTO openItemDTO=new OpenItemDTO();
        openItemDTO.setKey(key);
        openItemDTO.setValue(value);
        openItemDTO.setComment("添加新的商户配置");
        openItemDTO.setDataChangeCreatedBy(apolloConfig.getOperator());
        try {
            client.createItem(apolloConfig.getAppId(),apolloConfig.getEnv(),apolloConfig.getClusterName(),apolloConfig.getNamespace(),openItemDTO);
            releaseAllItem();
        } catch (Exception e) {
            LogUtil.error(logger, e,"推送商户配置到apollo失败，key:{0}  value:{1}" ,key ,value);
            throw new SystemException(ExceptionEnum.E10052);
        }
        LogUtil.info(logger, "推送商户配置到apollo成功，key:{0}  value:{1}" ,key ,value);
    }

    /**
     * 更新商户配置到apollo
     * @param entity
     * @return
     */
    public void updateItemToApollo(ChannelMerchantInfoEntity entity){
        String key=String.valueOf(entity.getId());
        String value=JSON.toJSONStringWithDateFormat(entity,"yyyy-MM-dd HH:mm:ss");
        OpenItemDTO openItemDTO=new OpenItemDTO();
        openItemDTO.setKey(key);
        openItemDTO.setValue(value);
        openItemDTO.setComment("更新商户配置信息");
        openItemDTO.setDataChangeCreatedBy(apolloConfig.getOperator());
        try {
            client.createOrUpdateItem(apolloConfig.getAppId(),apolloConfig.getEnv(),apolloConfig.getClusterName(),apolloConfig.getNamespace(),openItemDTO);
            releaseAllItem();
        } catch (Exception e) {
            LogUtil.error(logger, e, "更新商户配置到apollo失败，key:{0}  value:{1}" ,key ,value);
            throw new SystemException(ExceptionEnum.E10053);
        }
        LogUtil.info(logger, "更新商户配置到apollo成功，key:{0}  value:{1}" ,key ,value);

    }

    /**
     * 发布apollo上的所有配置
     * @return
     */
    private void releaseAllItem(){
        NamespaceReleaseDTO namespaceReleaseDTO = new NamespaceReleaseDTO();
        namespaceReleaseDTO.setReleaseTitle("releaseTitle");
        namespaceReleaseDTO.setReleaseComment("releaseComment");
        namespaceReleaseDTO.setReleasedBy(apolloConfig.getOperator());
        try {
            client.publishNamespace(apolloConfig.getAppId(), apolloConfig.getEnv(), apolloConfig.getClusterName(), apolloConfig.getNamespace(), namespaceReleaseDTO);
        } catch (Exception e) {
            LogUtil.error(logger, e, "发布apollo商户配置失败");
            throw new SystemException(ExceptionEnum.E10054);
        }
        LogUtil.info(logger, "发布apollo商户配置成功");

    }

    /**
     * 获取命名空间下的所有商户配置
     * @return
     */
    public List<ChannelMerchantInfoEntity> getItemsByNamespace(){
        List<ChannelMerchantInfoEntity> allMerchantInfo = null;
        try {
            OpenNamespaceDTO namespaceDTO = client.getNamespace(apolloConfig.getAppId(), apolloConfig.getEnv(), apolloConfig.getClusterName(),apolloConfig.getNamespace());
            List<OpenItemDTO> items = namespaceDTO.getItems();
            allMerchantInfo = items.stream().map(item -> {
                return JSON.parseObject(item.getValue(), ChannelMerchantInfoEntity.class);
            }).collect(Collectors.toList());
        } catch (Exception e) {
            LogUtil.error(logger, e, "从apollo中获取所有商户配置失败");
            throw new SystemException(ExceptionEnum.E10051);
        }
        LogUtil.info(logger, "从apollo中获取所有商户配置成功");
        return allMerchantInfo;
    }

    /**
     * 根据支付方式获取商户配置
     * @param channelPay
     * @return
     */
    public List<ChannelMerchantInfoEntity> selectByPayType(ChannelPayEntity channelPay){
        String payType = channelPay.getPayType().toString();
        String bizCode = channelPay.getBizCode();
        List<ChannelMerchantInfoEntity> channelMerchantInfoEntities= null;
        try {
            channelMerchantInfoEntities = getItemsByNamespace().stream().filter(merchantInfoEntity->bizCode.equals(merchantInfoEntity.getBizCode()) && payType.equals(merchantInfoEntity.getPayChannel()) && Integer.valueOf(1).equals(merchantInfoEntity.getMerchantStatus())).collect(Collectors.toList());

        } catch (Exception e) {
            LogUtil.error(logger, e, "根据支付方式获取商户配置出现异常");
            throw new SystemException(ExceptionEnum.FAIL);
        }
        LogUtil.info(logger, "根据支付方式获取商户配置成功 返回{0}", channelMerchantInfoEntities);
        return channelMerchantInfoEntities;
    }

    /**
     * 根据支付方式和商户号获取配置
     * @return
     */
    public ChannelMerchantInfoEntity selectByPayChannelAndMerchantNo(String payType, String MerchantNo){
        ChannelMerchantInfoEntity result;
        List<ChannelMerchantInfoEntity> merchantInfoList = null;
        try {
            merchantInfoList = getItemsByNamespace().stream().filter(merchantInfoEntity -> payType.equals(merchantInfoEntity.getPayChannel()) && MerchantNo.equals(merchantInfoEntity.getMerchantNo())).collect(Collectors.toList());
        } catch (Exception e) {
            LogUtil.error(logger, "根据支付方式和商户号获取商户配置出现异常");
            throw new SystemException(ExceptionEnum.FAIL);
        }
        //如果没有相应配置就返回null
        if(CollectionUtils.isEmpty(merchantInfoList)){
            LogUtil.info(logger,"根据支付方式和商户号找不到相应的商户配置");
            return null;
        }else {
            result = merchantInfoList.get(0);
            LogUtil.info(logger,"根据支付方式和商户号获取配置成功 返回{0}", result);
            return result;
        }
    }

    /**
     * 根据支付方式、商户号和业务线code获取配置
     * @return
     */
    public ChannelMerchantInfoEntity selectByPayChannelAndMerchantNoAndBizCode(String payType, String merchantNo, String bizCode){
        ChannelMerchantInfoEntity result;
        List<ChannelMerchantInfoEntity> merchantInfoList = null;
        //兼容逻辑,避免老的MQ来查时查不到商户配置
        if (StringUtils.isEmpty(bizCode)) {
            bizCode = BusinessCodeEnum.WANLIMU.getBizCode();
        }
        try {
            String finalBizCode = bizCode;
            merchantInfoList = getItemsByNamespace().stream().filter(merchantInfoEntity -> payType.equals(merchantInfoEntity.getPayChannel()) && merchantNo.equals(merchantInfoEntity.getMerchantNo()) && finalBizCode.equals(merchantInfoEntity.getBizCode())).collect(Collectors.toList());
        } catch (Exception e) {
            LogUtil.error(logger, "根据支付方式、商户号和业务线码获取商户配置出现异常");
            throw new SystemException(ExceptionEnum.FAIL);
        }
        //如果没有相应配置就返回null
        if(CollectionUtils.isEmpty(merchantInfoList)){
            LogUtil.info(logger,"根据支付方式、商户号和业务线码找不到相应的商户配置");
            return null;
        }else {
            result = merchantInfoList.get(0);
            LogUtil.info(logger,"根据支付方式、商户号和业务线码获取配置成功 返回{0}", result);
            return result;
        }
    }
}
